class Util {
  static setElementWidth(element, width) {
    element.style.width = width + "px";
  }
  static setElementHeight(element, height) {
    element.style.height = height + "px";
  }

  static addElementWidth(element, offsetWidth) {
    Util.setElementWidth(element, Util.getElementWidth(element) + offsetWidth);
  }
  static getElementWidth(element) {
    if (element.style.width) {
      return parseFloat(element.style.width);
    }
    return element.getBoundingClientRect().width;
  }
  static getElementHeight(element) {
    if (element.style.height) {
      return parseFloat(element.style.height);
    }
    return element.getBoundingClientRect().height;
  }
  static getElementOffsetLeft(element) {
    let offsetLeft = element.offsetLeft;
    let parent = element.offsetParent;
    while (parent !== null) {
      offsetLeft += parent.offsetLeft;
      parent = parent.offsetParent;
    }
    return offsetLeft;
  }

  static getElementOffsetTop(element) {
    let offsetTop = element.offsetTop;
    let parent = element.offsetParent;
    while (parent !== null) {
      offsetTop += parent.offsetTop;
      parent = parent.offsetParent;
    }
    return offsetTop;
  }
  // static setElementStyleWidthAndHeight(element, width, height) {
  //   element.style.width = width + "px";
  //   element.style.height = height + "px";
  // }

  static isNearElementBottomSide(element, y, distance = 10) {
    let bottom = element.getBoundingClientRect().bottom;
    if (y < bottom && y > bottom - distance) {
      return true;
    }
    return false;
  }
  static isNearElementRightSide(element, x, distance = 10) {
    let right = element.getBoundingClientRect().right;
    if (x < right && x > right - distance) {
      return true;
    }
    return false;
  }
  static hiddenElement(element) {
    element.style.visibility = "hidden";
  }
  static visibleElement(element) {
    element.style.visibility = "visible";
  }
  // static isNearElementBorder(
  //   element,
  //   x,
  //   y,
  //   topDistance = 10,
  //   rightDistance = 10,
  //   bottomDistance = 10,
  //   leftDistance = 10
  // ) {
  //   let rect = element.getBoundingClientRect();
  //   let left = rect.left;
  //   let right = rect.right;
  //   let top = rect.top;
  //   let bottom = rect.bottom;
  //   if (
  //     x < left + leftDistance ||
  //     x > right - rightDistance ||
  //     y < top + topDistance ||
  //     y > bottom - bottomDistance
  //   ) {
  //     return true;
  //   }
  //   return false;
  // }

  // static copyStyle(from, to) {
  //   to.style.cssText = from.style.cssText;
  // }
  // static copyTextContentAndStyle(from, to) {
  //   Util.copyStyle(from, to);
  //   to.textContent = from.textContent;
  // }
}

class TextInfo {
  constructor() {
    this.info = new Map();
  }
  set(row, column, text) {
    if (!this.info.get(row)) {
      this.info.set(row, new Map());
    }
    this.info.get(row).set(column, text);
  }
  get(row, column) {
    let rowMap = this.info.get(row);
    if (!rowMap) {
      return null;
    }
    if (!rowMap.get(column)) {
      return null;
    }
    return rowMap.get(column);
  }
}
class Data {
  constructor(rowCount = 10, columnCount = 10) {
    this.rowCount = rowCount;
    this.columnCount = columnCount;
    this.rowHeight = new Map();
    this.columnWidth = new Map();
    this.textInfo = new TextInfo();
  }
  setText(row, column, text) {
    this.textInfo.set(row, column, text);
  }
  getText(row, column) {
    return this.textInfo.get(row, column);
  }
  changeRowHeight(row, height) {
    this.rowHeight.set(row, height);
  }
  changeColumnWidth(column, width) {
    this.columnWidth.set(column, width);
  }
  addRow() {
    this.rowCount++;
  }
  addColumn() {
    this.columnCount++;
  }
  getRowHeight(row) {
    if (this.rowHeight.get(row)) {
      return this.rowHeight.get(row);
    }
    return Data.DEFAULT_ROW_HEIGHT;
  }
  isDefaultRowHeight(row) {
    return !this.rowHeight.get(row);
  }
  isDefaultColumnWidth(column) {
    return !this.columnWidth.get(column);
  }
  getColumnWidth(column) {
    if (this.columnWidth.get(column)) {
      return this.columnWidth.get(column);
    }
    return Data.DEFAULT_COLUMN_WIDTH;
  }
  // 返回列之间的宽度 左闭右开
  getWidthBetweenColumns(beginColumn, endColumn) {
    let sum = 0;
    for (let i = beginColumn; i < endColumn; i++) {
      let width = this.getColumnWidth(i);
      // if (width) {
      //   sum += width;
      // } else {
      //   sum += Data.DEFAULT_COLUMN_WIDTH;
      // }
      sum += width;
    }
    return sum;
  }
  // 返回行之间的高度 左闭右开
  getHeightBetweenRows(beginRow, endRow) {
    let sum = 0;
    for (let i = beginRow; i < endRow; i++) {
      let height = this.getRowHeight(i);
      // if (height) {
      //   sum += height;
      // } else {
      //   sum += Data.DEFAULT_ROW_HEIGHT;
      // }
      sum += height;
    }
    return sum;
  }

  insertRow(row) {
    this.rowCount++;
    let newRowHeight = new Map();
    this.rowHeight.forEach((val, key) => {
      if (key >= row) {
        newRowHeight.set(key + 1, val);
      } else {
        newRowHeight.set(key, val);
      }
    });
    this.rowHeight = newRowHeight;
  }
  removeRow(row) {
    this.rowCount--;
    let newRowHeight = new Map();
    this.rowHeight.delete(row);
    this.rowHeight.forEach((val, key) => {
      if (key >= row) {
        newRowHeight.set(key - 1, val);
      } else {
        newRowHeight.set(key, val);
      }
    });
    this.rowHeight = newRowHeight;
  }
  insertColumn(column) {
    this.columnCount++;

    let newColumnWidth = new Map();
    this.columnWidth.forEach((val, key) => {
      if (key >= column) {
        newColumnWidth.set(key + 1, val);
      } else {
        newColumnWidth.set(key, val);
      }
    });
    this.columnWidth = newColumnWidth;
  }
  removeColumn(column) {
    this.column--;
    let newColumnWidth = new Map();
    this.columnWidth.delete(column);
    this.columnWidth.forEach((val, key) => {
      if (key >= column) {
        newColumnWidth.set(key - 1, val);
      } else {
        newColumnWidth.set(key, val);
      }
    });
    this.columnWidth = newColumnWidth;
  }
}

Data.DEFAULT_ROW_HEIGHT = 30;
Data.DEFAULT_COLUMN_WIDTH = 100;
Data.DEFAULT_ROW_HEADER_WIDTH = 50;
Data.DEFAULT_WIDTH_OFFSET = 100;

class ResizeManager {
  constructor(table) {
    this.start = false;
    this.element = null;
    this.left = null;
    this.top = null;
    this.width = null;
    this.height = null;
    this.setStyle = false;
    this.line = null;
    this.table = table;
  }
  begin(event) {
    let element = event.target;
    let classList = element.classList;
    if (classList.contains("row-resize") || classList.contains("col-resize")) {
      this.start = true;
      this.element = element;
      this.left = Util.getElementOffsetLeft(element);
      this.top = Util.getElementOffsetTop(element);
      this.width = Util.getElementWidth(element);
      this.height = Util.getElementHeight(element);
      this.row = this.table.getRowByPageY(event.pageY);
      this.column = this.table.getColumnByPageX(event.pageX);
    }
  }
  resize(event) {
    if (!this.start) {
      return;
    }
    let element = this.element;
    let classList = element.classList;
    if (!this.setStyle) {
      this.table.table
        .querySelectorAll(".col-header, .row-header")
        .forEach((item) => item.classList.add("no-resize"));
      classList.remove("no-resize");
      classList.add("resize");
      let line;
      if (classList.contains("col-header")) {
        this.table.table.classList.add("col-resize");
        line = this.table.colResizeLine;
      } else if (classList.contains("row-header")) {
        this.table.table.classList.add("row-resize");
        line = this.table.rowResizeLine;
      }
      element.appendChild(line);
      line.style.visibility = "visible";
      this.line = line;
      this.setStyle = true;
    }

    if (classList.contains("col-header")) {
      let newWidth = event.pageX - this.left;
      if (newWidth < Table.MIN_COLUMN_WIDTH) {
        newWidth = Table.MIN_COLUMN_WIDTH;
      }
      let offsetWidth = newWidth - this.width;
      this.width = newWidth;
      let header = this.table.table.querySelector(".col-headers");
      if (offsetWidth > 0) {
        Util.addElementWidth(this.table.table, offsetWidth);
        Util.addElementWidth(header, offsetWidth);
        Util.setElementWidth(element, newWidth);
      } else {
        Util.setElementWidth(element, newWidth);
        Util.addElementWidth(header, offsetWidth);
      }

      // } else {
      //   this.table.addWidth(-this.width);
      //   Util.setElementWidth(element, 0);
      //   this.width = 0;
      // }
    } else if (classList.contains("row-header")) {
      let newHeight = event.pageY - this.top;
      if (newHeight < Table.MIN_COLUMN_WIDTH) {
        newHeight = Table.MIN_COLUMN_WIDTH;
      }
      this.height = newHeight;
      Util.setElementHeight(element, newHeight);
      // } else {
      //   Util.setElementHeight(element, 0);
      // }
    }
  }
  end(event) {
    if (this.start) {
      let classList = this.element.classList;
      this.resize(event);
      if (classList.contains("col-header")) {
        let width = Util.getElementWidth(this.element);
        this.table.changeColumnWidth(this.column, width);
        let header = this.table.table.querySelector(".col-headers");
        Util.setElementWidth(this.table.table, Util.getElementWidth(header));
        this.table
          .getCellsByColumn(this.column)
          .forEach((item) => Util.setElementWidth(item, width));
      } else if (classList.contains("row-header")) {
        let height = Util.getElementHeight(this.element);
        this.table.changeRowHeight(this.row, height);
        this.table
          .getCellsByRow(this.row)
          .forEach((item) => Util.setElementHeight(item, height));
      }
      if (this.setStyle) {
        this.table.table
          .querySelectorAll(".col-header, .row-header")
          .forEach((item) => item.classList.remove("no-resize"));
        classList.remove("resize");
        if (classList.contains("col-header")) {
          this.table.table.classList.remove("col-resize");
        } else if (classList.contains("row-header")) {
          this.table.table.classList.remove("row-resize");
        }
        this.line.style.visibility = "hidden";
        this.setStyle = false;
      }
    }
    this.start = false;
  }
  cursorStyle(event) {
    let element = event.target;
    let classList = element.classList;
    if (classList.contains("col-header")) {
      if (Util.isNearElementRightSide(element, event.clientX)) {
        element.classList.add("col-resize");
      } else {
        element.classList.remove("col-resize");
      }
    } else if (classList.contains("row-header")) {
      if (Util.isNearElementBottomSide(element, event.clientY)) {
        element.classList.add("row-resize");
      } else {
        element.classList.remove("row-resize");
      }
    }
  }
}
class Editor {
  constructor(table) {
    this.editElement = null;
    this.editBorder = table.editBorder;
    this.selectedRowHeader = null;
    this.selectedColumnHeader = null;
    this.table = table;
    this.row = null;
    this.column = null;
    this._initEventListener();
  }
  _initEventListener() {
    this.editBorder.addEventListener("blur", (event) => {
      let text = this.editBorder.textContent;
      this.editElement.textContent = text;
      if (text) {
        this.table.data.setText(this.row, this.column, text);
      }
      this.selectedColumnHeader.classList.remove("selected");
      this.selectedRowHeader.classList.remove("selected");
    });
  }
  show(event) {
    let element = event.target;
    if (!element.classList.contains("cell")) {
      return;
    }
    let column = this.table.getColumnByPageX(event.pageX);
    let row = this.table.getRowByPageY(event.pageY);
    this.selectedColumnHeader = this.table.table.querySelector(
      `.col-headers .col-header:nth-child(${column + 1})`
    );
    this.selectedRowHeader = this.table.table.querySelector(
      `.row-headers .row-header:nth-child(${row}`
    );
    this.selectedColumnHeader.classList.add("selected");
    this.selectedRowHeader.classList.add("selected");
    this.editBorder.textContent = element.textContent;
    element.textContent = "";
    element.appendChild(this.editBorder);
    Util.visibleElement(this.editBorder);
    this.editBorder.focus();
    this.editElement = element;
    this.row = row;
    this.column = column;
  }
  hidden() {
    this.editBorder.blur();
  }
}
class Selector {
  constructor(table) {
    this.table = table;
    this.selectTopBorder = table.selectTopBorder;
    this.selectLeftBorder = table.selectLeftBorder;
    this.selectBottomBorder = table.selectBottomBorder;
    this.selectRightBorder = table.selectRightBorder;
    this.selectDot = table.selectDot;

    this.start = false;
    this.show = false;
    this.beginRow = null;
    this.beginColumn = null;
    this.endRow = null;
    this.endColumn = null;
  }
  hidden() {
    if (!this.show) return;
    this._hiddenBorder();
    this._hiddenBackgroundColor();
    this._removeHeaderSelectedStyle();
    this.show = false;
  }
  _hiddenBorder() {
    Util.hiddenElement(this.selectTopBorder);
    Util.hiddenElement(this.selectLeftBorder);
    Util.hiddenElement(this.selectBottomBorder);
    Util.hiddenElement(this.selectRightBorder);
    Util.hiddenElement(this.selectDot);
  }
  _hiddenBackgroundColor() {
    let leftTopRow = Math.min(this.beginRow, this.endRow);
    let leftTopColumn = Math.min(this.beginColumn, this.endColumn);
    let rightBottomRow = Math.max(this.beginRow, this.endRow);
    let rightBottomColumn = Math.max(this.beginColumn, this.endColumn);

    for (let i = leftTopRow; i <= rightBottomRow; i++) {
      // console.log(i);
      let cells = this.table.getCellsByRow(i);

      for (let j = leftTopColumn; j <= rightBottomColumn; j++) {
        cells[j - 1].classList.remove("selected");
      }
    }
  }
  _removeHeaderSelectedStyle() {
    let leftTopRow = Math.min(this.beginRow, this.endRow);
    let leftTopColumn = Math.min(this.beginColumn, this.endColumn);
    let rightBottomRow = Math.max(this.beginRow, this.endRow);
    let rightBottomColumn = Math.max(this.beginColumn, this.endColumn);

    let rowHeaders = this.table.getRowHeaders();
    let columnHeaders = this.table.getColumnHeaders();

    for (let i = leftTopRow; i <= rightBottomRow; i++) {
      rowHeaders[i - 1].classList.remove("selected");
    }
    for (let i = leftTopColumn; i <= rightBottomColumn; i++) {
      columnHeaders[i - 1].classList.remove("selected");
    }
  }

  _visibleBorder() {
    Util.visibleElement(this.selectTopBorder);
    Util.visibleElement(this.selectLeftBorder);
    Util.visibleElement(this.selectBottomBorder);
    Util.visibleElement(this.selectRightBorder);
    Util.visibleElement(this.selectDot);
  }
  begin(event) {
    let element = event.target;
    this.hidden();
    if (!element.classList.contains("cell")) {
      return;
    }
    this.start = true;
    this.beginRow = this.table.getRowByPageY(event.pageY);
    this.beginColumn = this.table.getColumnByPageX(event.pageX);
    this.endRow = this.beginRow;
    this.endColumn = this.beginColumn;
    this._show();
  }
  selected(event) {
    if (!this.start || !event.target.classList.contains("cell")) {
      return;
    }
    let endRow = this.table.getRowByPageY(event.pageY);
    let endColumn = this.table.getColumnByPageX(event.pageX);

    if (this.endRow === endRow && this.endColumn === endColumn) {
      return;
    }
    this.hidden();
    this.endRow = endRow;
    this.endColumn = endColumn;
    this._show();
  }
  end(event) {
    this.start = false;
  }
  _show() {
    this._showBorder();
    this._showBackgroundColor();
    this._addHeaderSelectedStyle();
    this.show = true;
  }
  _showBorder() {
    let leftTopRow = Math.min(this.beginRow, this.endRow);
    let leftTopColumn = Math.min(this.beginColumn, this.endColumn);
    let rightBottomRow = Math.max(this.beginRow, this.endRow);
    let rightBottomColumn = Math.max(this.beginColumn, this.endColumn);

    let width = this.table.getWidthBetweenColumns(
      leftTopColumn,
      rightBottomColumn + 1
    );
    let height = this.table.getHeightBetweenRows(
      leftTopRow,
      rightBottomRow + 1
    );
    let leftTopCell = this.table.getCellByRowColumn(leftTopRow, leftTopColumn);
    let rightBottomCell = this.table.getCellByRowColumn(
      rightBottomRow,
      rightBottomColumn
    );
    Util.setElementWidth(this.selectTopBorder, width + 2);

    Util.setElementHeight(this.selectLeftBorder, height + 2);

    Util.setElementWidth(this.selectBottomBorder, width - 2);

    Util.setElementHeight(this.selectRightBorder, height - 2);

    leftTopCell.appendChild(this.selectTopBorder);

    leftTopCell.appendChild(this.selectLeftBorder);

    rightBottomCell.appendChild(this.selectBottomBorder);
    rightBottomCell.appendChild(this.selectRightBorder);
    rightBottomCell.appendChild(this.selectDot);

    this._visibleBorder();
  }
  _showBackgroundColor() {
    let leftTopRow = Math.min(this.beginRow, this.endRow);
    let leftTopColumn = Math.min(this.beginColumn, this.endColumn);
    let rightBottomRow = Math.max(this.beginRow, this.endRow);
    let rightBottomColumn = Math.max(this.beginColumn, this.endColumn);

    for (let i = leftTopRow; i <= rightBottomRow; i++) {
      let cells = this.table.getCellsByRow(i);
      for (let j = leftTopColumn; j <= rightBottomColumn; j++) {
        cells[j - 1].classList.add("selected");
      }
    }
    table
      .getCellByRowColumn(this.beginRow, this.beginColumn)
      .classList.remove("selected");
  }
  _addHeaderSelectedStyle() {
    let leftTopRow = Math.min(this.beginRow, this.endRow);
    let leftTopColumn = Math.min(this.beginColumn, this.endColumn);
    let rightBottomRow = Math.max(this.beginRow, this.endRow);
    let rightBottomColumn = Math.max(this.beginColumn, this.endColumn);

    let rowHeaders = this.table.getRowHeaders();
    let columnHeaders = this.table.getColumnHeaders();

    for (let i = leftTopRow; i <= rightBottomRow; i++) {
      rowHeaders[i - 1].classList.add("selected");
    }
    for (let i = leftTopColumn; i <= rightBottomColumn; i++) {
      columnHeaders[i - 1].classList.add("selected");
    }
  }
}

class Options {
  constructor(table) {
    this.table = table;
    this.rowOptions = table.rowOptions;
    this.columnOptions = table.columnOptions;
    this.row = null;
    this.column = null;
    this._initEventListener();
  }
  tryHidden(event) {
    if (event.target.classList.contains("option")) {
      return;
    }
    this._hidden();
  }
  _hidden() {
    Util.hiddenElement(this.rowOptions);
    Util.hiddenElement(this.columnOptions);
  }
  show(event) {
    if (event.target.classList.contains("row-header")) {
      this._hidden();
      this._showRowOptions(event.clientX, event.clientY);
    } else if (event.target.classList.contains("col-header")) {
      this._hidden();
      this._showColumnOptions(event.clientX, event.clientY);
    } else {
      return;
    }
    this.row = this.table.getRowByPageY(event.pageY);
    this.column = this.table.getColumnByPageX(event.pageX);
  }
  _showRowOptions(x, y) {
    this.rowOptions.style.top = y + "px";
    this.rowOptions.style.left = x + "px";
    Util.visibleElement(this.rowOptions);
  }

  _showColumnOptions(x, y) {
    this.columnOptions.style.top = y + "px";
    this.columnOptions.style.left = x + "px";
    Util.visibleElement(this.columnOptions);
  }
  _initEventListener() {
    this.rowOptions.addEventListener("click", (event) => {
      this._hidden();
      let element = event.target;
      if (element.classList.contains("insert-row")) {
        this.table.insertRow(this.row);
      } else if (element.classList.contains("remove-row")) {
        this.table.removeRow(this.row);
      }
    });

    this.columnOptions.addEventListener("click", (event) => {
      this._hidden();
      let element = event.target;
      if (element.classList.contains("insert-col")) {
        this.table.insertColumn(this.column);
      } else if (element.classList.contains("remove-col")) {
        this.table.removeColumn(this.column);
      }
    });
  }
}
class Table {
  constructor(data) {
    this.data = data;
    this._initDOM();
    this._initEventListener();
  }

  _initDOM() {
    this._initTable();
    this._initThead();
    this._initTbody();
    this._initResizeLine();
    this._initEditBorder();
    this._initSelectedBorder();
    this._initRowColumnOptions();
    document.body.appendChild(this.table);
  }
  _initRowColumnOptions() {
    this._initRowOptions();
    this._initColumnOptions();
  }
  _initRowOptions() {
    let rowOptions = document.createElement("div");
    rowOptions.classList.add("options");
    rowOptions.classList.add("row-options");

    let insertRowOption = document.createElement("div");
    insertRowOption.classList.add("option");
    insertRowOption.classList.add("insert-row");
    insertRowOption.textContent = "插入整行";

    let removeRowOption = document.createElement("div");
    removeRowOption.classList.add("option");
    removeRowOption.classList.add("remove-row");
    removeRowOption.textContent = "删除整行";

    rowOptions.appendChild(insertRowOption);
    rowOptions.appendChild(removeRowOption);
    this.table.appendChild(rowOptions);
    this.rowOptions = rowOptions;
  }
  _initColumnOptions() {
    let colOptions = document.createElement("div");
    colOptions.classList.add("options");
    colOptions.classList.add("col-options");

    let insertColOption = document.createElement("div");
    insertColOption.classList.add("option");
    insertColOption.classList.add("insert-col");
    insertColOption.textContent = "插入整列";

    let removeColOption = document.createElement("div");
    removeColOption.classList.add("option");
    removeColOption.classList.add("remove-col");
    removeColOption.textContent = "删除整列";

    colOptions.appendChild(insertColOption);
    colOptions.appendChild(removeColOption);
    this.table.appendChild(colOptions);
    this.columnOptions = colOptions;
  }

  _initSelectedBorder() {
    this.selectTopBorder = document.createElement("div");
    this.selectTopBorder.classList.add("select-top-border");

    this.selectLeftBorder = document.createElement("div");
    this.selectLeftBorder.classList.add("select-left-border");

    this.selectBottomBorder = document.createElement("div");
    this.selectBottomBorder.classList.add("select-bottom-border");

    this.selectRightBorder = document.createElement("div");
    this.selectRightBorder.classList.add("select-right-border");

    this.selectDot = document.createElement("div");
    this.selectDot.classList.add("select-dot");
  }
  _initEditBorder() {
    this.editBorder = document.createElement("div");
    this.editBorder.classList.add("edit-border");
    this.editBorder.contentEditable = "true";
  }
  _initResizeLine() {
    this.rowResizeLine = document.createElement("div");
    this.rowResizeLine.classList.add("row-resize-line");
    this.colResizeLine = document.createElement("div");
    this.colResizeLine.classList.add("col-resize-line");
  }
  _initTable() {
    let table = document.createElement("div");
    table.classList.add("table");
    Util.setElementWidth(
      table,
      Data.DEFAULT_COLUMN_WIDTH * this.data.columnCount +
        Data.DEFAULT_ROW_HEADER_WIDTH +
        Data.DEFAULT_WIDTH_OFFSET
    );
    this.table = table;
  }
  // 0对应A 25对应Z
  getColumnHeaderTitle(col) {
    let result = "";
    while (col >= 0) {
      result = String.fromCharCode(65 + (col % 26)) + result;
      col = Math.floor(col / 26) - 1;
    }
    return result;
  }
  _initThead() {
    let data = this.data;
    let colHeaders = document.createElement("div");
    colHeaders.classList.add("col-headers");
    colHeaders.classList.add("row-container");

    Util.setElementWidth(
      colHeaders,
      Data.DEFAULT_COLUMN_WIDTH * data.columnCount +
        Data.DEFAULT_ROW_HEADER_WIDTH +
        Data.DEFAULT_WIDTH_OFFSET
    );

    let specialHeader = document.createElement("div");
    specialHeader.classList.add("special-header");
    colHeaders.appendChild(specialHeader);
    for (let i = 0; i < data.columnCount; i++) {
      let colHeader = document.createElement("div");
      colHeader.classList.add("col-header");
      colHeader.textContent = this.getColumnHeaderTitle(i);
      colHeaders.appendChild(colHeader);
    }
    this.table.appendChild(colHeaders);
  }
  _initTbody() {
    let rowHeadersAndCells = document.createElement("div");
    rowHeadersAndCells.classList.add("row-headers-and-cells");
    rowHeadersAndCells.classList.add("row-container");
    this.table.appendChild(rowHeadersAndCells);
    // Util.setElementWidth(
    //   rowHeadersAndCells,
    //   Data.DEFAULT_COLUMN_WIDTH * this.data.columnCount +
    //     Data.DEFAULT_ROW_HEADER_WIDTH +
    //     Data.DEFAULT_WIDTH_OFFSET
    // );
    rowHeadersAndCells.appendChild(this._createRowHeaders());
    rowHeadersAndCells.appendChild(this._createCells());
  }
  _createRowHeaders() {
    let rowHeaders = document.createElement("div");
    rowHeaders.classList.add("row-headers");
    rowHeaders.classList.add("row-container");
    for (let i = 0; i < this.data.rowCount; i++) {
      let rowHeader = document.createElement("div");
      rowHeader.textContent = i + 1 + "";
      rowHeader.classList.add("row-header");
      rowHeaders.appendChild(rowHeader);
    }
    return rowHeaders;
  }
  _createCells() {
    let cells = document.createElement("div");
    cells.classList.add("cells");
    for (let i = 0; i < this.data.rowCount; i++) {
      cells.appendChild(this._createRow(i + 1));
    }
    return cells;
  }

  _createRow(row) {
    let rowContainer = document.createElement("div");
    rowContainer.classList.add("row-container");
    // Util.setElementWidth(
    //   rowContainer,
    //   Data.DEFAULT_COLUMN_WIDTH * this.data.columnCount +
    //     Data.DEFAULT_WIDTH_OFFSET
    // );
    let isDefaultRowHeight = this.data.isDefaultRowHeight(row);
    let height = this.data.getRowHeight(row);
    for (let i = 0; i < this.data.columnCount; i++) {
      let cell = document.createElement("div");
      cell.classList.add("cell");
      if (!isDefaultRowHeight) {
        Util.setElementHeight(cell, height);
      }
      if (!this.data.isDefaultColumnWidth(i + 1)) {
        Util.setElementWidth(cell, this.data.getColumnWidth(i + 1));
      }
      rowContainer.appendChild(cell);
    }
    return rowContainer;
  }
  getCellsByColumn(column) {
    return this.table.querySelectorAll(
      `.cells .row-container .cell:nth-child(${column})`
    );
  }
  getCellsByRow(row) {
    return this.table.querySelectorAll(
      `.cells .row-container:nth-child(${row}) .cell`
    );
  }
  getCellByRowColumn(row, column) {
    return this.getCellsByRow(row)[column - 1];
  }
  changeRowHeight(row, height) {
    this.data.changeRowHeight(row, height);
  }
  changeColumnWidth(column, width) {
    this.data.changeColumnWidth(column, width);
  }
  getRowByPageY(pageY) {
    pageY -= Util.getElementOffsetTop(this.table);
    let row = 0;
    let height = Data.DEFAULT_ROW_HEIGHT;
    while (height <= pageY) {
      row++;
      if (this.data.rowHeight.has(row)) {
        height += this.data.rowHeight.get(row);
      } else {
        height += Data.DEFAULT_ROW_HEIGHT;
      }
    }
    return row;
  }
  getColumnByPageX(pageX) {
    pageX -= Util.getElementOffsetLeft(this.table);
    let column = 0;
    let width = Data.DEFAULT_ROW_HEADER_WIDTH;
    while (width <= pageX) {
      column++;
      if (this.data.columnWidth.has(column)) {
        width += this.data.columnWidth.get(column);
      } else {
        width += Data.DEFAULT_COLUMN_WIDTH;
      }
    }
    return column;
  }
  getRowHeaders() {
    return this.table.querySelectorAll(".row-headers .row-header");
  }
  getColumnHeaders() {
    return this.table.querySelectorAll(".col-headers .col-header");
  }

  addRow() {
    this.data.addRow();
    let rowHeaders = this.table.querySelector(".row-headers");
    let rowHeader = document.createElement("div");
    rowHeader.classList.add("row-header");
    rowHeader.textContent = this.data.rowCount;
    rowHeaders.appendChild(rowHeader);
    let cells = this.table.querySelector(".cells");
    cells.appendChild(this._createRow(this.data.rowCount));
  }
  addColumn() {
    this.data.addColumn();
    let header = this.table.querySelector(".col-headers");
    Util.addElementWidth(this.table, Data.DEFAULT_COLUMN_WIDTH);
    Util.addElementWidth(header, Data.DEFAULT_COLUMN_WIDTH);

    let colHeaders = this.table.querySelector(".col-headers");
    let colHeader = document.createElement("div");
    colHeader.textContent = this.getColumnHeaderTitle(
      this.data.columnCount - 1
    );
    colHeader.classList.add("col-header");
    colHeaders.appendChild(colHeader);
    let rowContainers = this.table.querySelectorAll(".cells .row-container");
    rowContainers.forEach((item, index) => {
      let cell = document.createElement("div");
      if (!this.data.isDefaultRowHeight(index + 1)) {
        Util.setElementHeight(cell, this.data.getRowHeight(index + 1));
      }
      cell.classList.add("cell");
      item.appendChild(cell);
    });
  }
  insertRow(row) {
    this.data.insertRow(row);
    let rowHeaders = this.table.querySelector(".row-headers");
    let rowHeader = document.createElement("div");
    rowHeader.classList.add("row-header");
    rowHeader.textContent = row + "";
    let rowHeaderList = this.getRowHeaders();
    for (let i = row; i <= rowHeaderList.length; i++) {
      rowHeaderList[i - 1].textContent = i + 1 + "";
    }
    rowHeaders.insertBefore(rowHeader, rowHeaderList[row - 1]);
    let cells = this.table.querySelector(".cells");
    let rowElements = this._createRow(row);
    cells.insertBefore(
      rowElements,
      cells.querySelector(`.row-container:nth-child(${row})`)
    );
  }

  removeRow(row) {
    this.data.removeRow(row);
    let rowHeaders = this.table.querySelector(".row-headers");
    let rowHeaderList = this.getRowHeaders();
    for (let i = row; i < rowHeaderList.length; i++) {
      rowHeaderList[i].textContent = i + "";
    }
    rowHeaders.removeChild(
      rowHeaders.querySelector(`.row-header:nth-child(${row})`)
    );
    let cells = this.table.querySelector(".cells");
    cells.removeChild(cells.querySelector(`.row-container:nth-child(${row})`));
  }

  insertColumn(column) {
    this.data.insertColumn(column);
    let header = this.table.querySelector(".col-headers");
    Util.addElementWidth(this.table, Data.DEFAULT_COLUMN_WIDTH);
    Util.addElementWidth(header, Data.DEFAULT_COLUMN_WIDTH);
    // 插入表头
    let columnHeaders = this.getColumnHeaders();
    for (let i = column - 1; i < columnHeaders.length; i++) {
      columnHeaders[i].textContent = this.getColumnHeaderTitle(i + 1);
    }
    let colHeader = document.createElement("div");
    colHeader.classList.add("col-header");
    colHeader.textContent = this.getColumnHeaderTitle(column - 1);

    let parent = columnHeaders[column - 1].parentNode;
    parent.insertBefore(colHeader, columnHeaders[column - 1]);

    // 插入表格
    let rowContainers = this.table.querySelectorAll(".cells .row-container");
    rowContainers.forEach((item, index) => {
      let cell = document.createElement("div");
      cell.classList.add("cell");
      if (!this.data.isDefaultRowHeight(index + 1)) {
        Util.setElementHeight(cell, this.data.getRowHeight(index + 1));
      }
      item.insertBefore(cell, item.querySelector(`.cell:nth-child(${column})`));
    });
  }

  removeColumn(column) {
    let columnWidth = this.data.getColumnWidth(column);
    this.data.removeColumn(column);
    let columnHeaders = this.getColumnHeaders();
    for (let i = column; i < columnHeaders.length; i++) {
      columnHeaders[i].textContent = this.getColumnHeaderTitle(i - 1);
    }
    let parent = columnHeaders[column - 1].parentNode;
    parent.removeChild(columnHeaders[column - 1]);

    let rowContainers = this.table.querySelectorAll(".cells .row-container");
    rowContainers.forEach((item) => {
      item.removeChild(item.querySelector(`.cell:nth-child(${column})`));
    });

    let header = this.table.querySelector(".col-headers");
    Util.addElementWidth(header, -columnWidth);
    Util.addElementWidth(this.table, -columnWidth);
  }
  getWidthBetweenColumns(beginColumn, endColumn) {
    return this.data.getWidthBetweenColumns(beginColumn, endColumn);
  }
  getHeightBetweenRows(beginRow, endRow) {
    return this.data.getHeightBetweenRows(beginRow, endRow);
  }
  _initEventListener() {
    let resize = new ResizeManager(this);
    let editor = new Editor(this);
    let selector = new Selector(this);
    let options = new Options(this);
    let scroll = new Scroll();
    this.table.addEventListener("dblclick", (event) => {
      editor.show(event);
    });
    this.table.addEventListener("keydown", (event) => {
      // 按下enter键
      if (event.keyCode === 13) {
        editor.hidden();
      }
    });
    this.table.addEventListener("mousedown", (event) => {
      selector.hidden();
      if (event.button === 0) {
        // 左键
        resize.begin(event);
        selector.begin(event);
        options.tryHidden(event);
      } else if (event.button === 2) {
        // 右键
        options.show(event);
      }
    });
    this.table.addEventListener("mousemove", (event) => {
      resize.cursorStyle(event);
      resize.resize(event);
      selector.selected(event);
    });
    document.addEventListener("mouseup", (event) => {
      resize.end(event);
      selector.end(event);
    });

    window.addEventListener("scroll", (event) => {
      scroll.scroll();
    });
    document.addEventListener("contextmenu", (event) => {
      event.preventDefault();
    });
  }
}

class Scroll {
  constructor(table) {
    this.table = table;
    this.previousScrollX = window.scrollX;
    this.previousScrollY = window.scrollY;
    this.offsetX = 0;
    this.offsetY = 0;
  }
  scroll() {
    this.offsetX += window.scrollX - this.previousScrollX;
    this.offsetY += window.scrollY - this.previousScrollY;
    this.previousScrollX = window.scrollX;
    this.previousScrollY = window.scrollY;

    if (this.offsetY > Data.DEFAULT_ROW_HEIGHT - 1) {
      this.offsetY = 0;
      table.addRow();
    }
    if (this.offsetX > Data.DEFAULT_COLUMN_WIDTH - 1) {
      this.offsetX = 0;
      table.addColumn();
    }
  }
}

Table.MIN_ROW_HEIGHT = 30;
Table.MIN_COLUMN_WIDTH = 30;

let table = new Table(new Data(50, 30));
